package com.example.tool.subject;

import com.example.tool.entity.ConfigEntity;
import com.example.tool.module.ModuleInformation;
import com.example.tool.module.ModuleInputEnum;
import com.example.tool.ui.SwingViewWrapper;
import com.example.tool.utils.ActionToolUtil;
import com.example.tool.utils.FileUtil;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.remote.RemoteConfiguration;
import com.intellij.execution.remote.RemoteConfigurationType;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.ide.util.projectWizard.JavaModuleBuilder;
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
import com.intellij.ide.util.projectWizard.ProjectWizardStepFactory;
import com.intellij.ide.util.projectWizard.SettingsStep;
import com.intellij.ide.util.projectWizard.WizardContext;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.module.JavaModuleType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.CompilerModuleExtension;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.SwingUtilities;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@SuppressWarnings("SpellCheckingInspection")
public class HToolModuleBuilder extends JavaModuleBuilder {
  private static final Logger LOG = Logger.getInstance(HToolModuleBuilder.class);
  private static HToolModuleWizardStep hToolModuleWizardStep;
  private static HToolModuleBuilder htoolModuleBuilder;

  private HToolModuleBuilder() {
  }

  @Override
  public boolean isAvailable() {
    return true;
  }

  public static HToolModuleBuilder getInstance() {
    if (htoolModuleBuilder == null) {
      htoolModuleBuilder = new HToolModuleBuilder();
    }
    return htoolModuleBuilder;
  }

  @Override
  public ModuleType<?> getModuleType() {
    return new HToolModuleType();
  }

  @Override
  public int getWeight() {
    return ModuleInformation.MODULE_WEIGHT;
  }

  @Override
  public String getParentGroup() {
    return JavaModuleType.JAVA_GROUP;
  }

  @Override
  public void setupRootModel(@NotNull ModifiableRootModel model) throws ConfigurationException {
    try {
      LOG.info("构建SeeyonTool项目开始");
      sourcePath();
      super.setupRootModel(model);
      compilePath(model);
      runConfigurable(model);
      LOG.info("构建SeeyonTool项目结束");
    } catch (Exception e) {
      LOG.info("创建SeeyonTool项目出错：" + e.getMessage(), e);
      throw new ConfigurationException(e.getMessage());
    }
  }

  @Nullable
  @Override
  public ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) {
    hToolModuleWizardStep = HToolModuleWizardStep.getInstance();
    return hToolModuleWizardStep;
  }

  @Override
  public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) {
    ProjectWizardStepFactory projectWizardStepFactory = ProjectWizardStepFactory.getInstance();
    return projectWizardStepFactory.createJavaSettingsStep(settingsStep, this, this::isSuitableSdkType);
  }


  /**
   * 设置项目的源码路径
   */
  private void sourcePath() {
    List<Pair<String, String>> sourcePaths = new ArrayList<>();
    SwingViewWrapper swingViewWrapper = hToolModuleWizardStep.getSwingViewWrapper();
    Map<ModuleInputEnum, String> values = swingViewWrapper.getValues();
    String plugID = values.get(ModuleInputEnum.PLUG_ID);
    String contentEntryPath = getContentEntryPath();
    if (contentEntryPath != null) {
      Path srcPath = Path.of(contentEntryPath, "src");
      Path srcPlugIDPath = Path.of(contentEntryPath, "src_" + plugID);
      sourcePaths.add(Pair.create(srcPath.toString(), ""));
      sourcePaths.add(Pair.create(srcPlugIDPath.toString(), ""));
      super.setSourcePaths(sourcePaths);
    }
  }

  /**
   * 设置项目的编译路径
   * @param model 模块
   */
  private void compilePath(ModifiableRootModel model) {
    Project project = model.getProject();
    String basePath = project.getBasePath();
    if (basePath != null) {
      SwingViewWrapper swingViewWrapper = hToolModuleWizardStep.getSwingViewWrapper();
      Map<ModuleInputEnum, String> values = swingViewWrapper.getValues();
      String buildPath = values.get(ModuleInputEnum.BUILD_PATH);
      Path path = Path.of(basePath, buildPath, "WEB-INF", "classes");
      LOG.info("设置项目的编译路径为：" + path);
      CompilerModuleExtension instance = model.getModuleExtension(CompilerModuleExtension.class);
      instance.inheritCompilerOutputPath(false);
      instance.setExcludeOutput(true);
      instance.setCompilerOutputPath(path.toString());
    }
  }

  /**
   * 项目结构配置
   * @param model 模块
   */
  private void runConfigurable(ModifiableRootModel model) {
    Application application = ApplicationManager.getApplication();
    SwingUtilities.invokeLater(() -> {
      Project project = model.getProject();
      SwingViewWrapper swingViewWrapper = hToolModuleWizardStep.getSwingViewWrapper();
      Map<ModuleInputEnum, String> values = swingViewWrapper.getValues();
      String pluginID = values.get(ModuleInputEnum.PLUG_ID);
      String rootPath = values.get(ModuleInputEnum.ROOT_PATH);
      Module[] modules = ModuleManager.getInstance(project).getModules();
      if (modules.length < 1) return;
      RunManager runManager = RunManager.getInstance(project);
      RemoteConfigurationType instance = RemoteConfigurationType.getInstance();
      RunnerAndConfigurationSettings runnerAndConfigurationSettings = runManager.createConfiguration(ModuleInformation.DEBUG_NAME, instance);
      RunConfiguration configuration = runnerAndConfigurationSettings.getConfiguration();
      if (!(configuration instanceof RemoteConfiguration remoteConfiguration)) return;
      remoteConfiguration.setModule(modules[0]);
      remoteConfiguration.PORT = values.get(ModuleInputEnum.DEBUG_PORT);
      runManager.addConfiguration(runnerAndConfigurationSettings);
      runManager.setSelectedConfiguration(runnerAndConfigurationSettings);
      application.runWriteAction(() -> {
        try {
          LOG.info("创建文件开始");
          createFile(model, values);
          LOG.info("创建文件结束");
          LOG.info("添加依赖开始");
          addLibrary(model, rootPath, pluginID);
          LOG.info("添加依赖结束");
        } catch (Exception e) {
          LOG.info("创建文件出错：" + e.getMessage(), e);
          throw new RuntimeException(e);
        }
      });
    });
    // application.invokeLater(() -> {});
  }

  /**
   * 添加项目依赖
   * @param model    项目模块
   * @param pathJar  jar包路径
   * @param pluginID 插件ID
   */
  private void addLibrary(ModifiableRootModel model, String pathJar, String pluginID) {
    // 调用写线程
    final List<Pair<String, String>> pairList = new ArrayList<>();
    FileUtil.getAllJar(pathJar, value -> pairList.add(Pair.create(value, null)));
    LibraryTable libraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(model.getProject());
    Library library = libraryTable.createLibrary(pluginID);
    for (Pair<String, String> libInfo : pairList) {
      final String moduleLibraryPath = libInfo.first;
      final String sourceLibraryPath = libInfo.second;
      Library.ModifiableModel modifiableModel = library.getModifiableModel();
      File libraryRoot = new File(moduleLibraryPath);
      modifiableModel.addRoot(VfsUtil.getUrlForLibraryRoot(libraryRoot), OrderRootType.CLASSES);
      if (sourceLibraryPath != null) {
        File file = new File(sourceLibraryPath);
        modifiableModel.addRoot(VfsUtil.getUrlForLibraryRoot(file), OrderRootType.SOURCES);
      }
      modifiableModel.commit();
    }
    if (!pairList.isEmpty()) {
      ModuleRootModificationUtil.addDependency(model.getModule(), library);
    }
  }

  /**
   * 创建项目文件
   * @param model  项目模块
   * @param values 接收的参数集合
   */
  @SuppressWarnings("Duplicates")
  private void createFile(ModifiableRootModel model, Map<ModuleInputEnum, String> values) throws Exception {
    Project project = model.getProject();
    PsiManager psiManager = PsiManager.getInstance(project);
    String basePath = project.getBasePath();
    if (basePath != null) {
      LocalFileSystem localFileSystem = LocalFileSystem.getInstance();
      String rootPath = values.get(ModuleInputEnum.ROOT_PATH);
      String buildPath = values.get(ModuleInputEnum.BUILD_PATH);
      String plugID = values.get(ModuleInputEnum.PLUG_ID);
      VirtualFile fileByNioFile = localFileSystem.findFileByNioFile(Path.of(basePath));
      if (fileByNioFile != null) {
        // 刷新项目中的文件信息 判断能否创建对应的文件
        fileByNioFile.refresh(false, true);
      }
      Path path = Path.of(basePath, "src_" + plugID);
      // 创建Java
      VirtualFile plugIDVir = localFileSystem.findFileByNioFile(path);
      VirtualFile virtualFileClass = FileUtil.createDirectories(this, plugIDVir, "com", "seeyon", "apps", plugID);
      PsiDirectory classPsiDirectory = psiManager.findDirectory(virtualFileClass);
      String className = FileUtil.upperFirstCase(plugID) + "PluginInit";
      values.put(ModuleInputEnum.CLASS_NANE, className);
      FileUtil.createClass(project, classPsiDirectory, values, "/java/PluginInit.java.sample");
      if (classPsiDirectory != null) {
        classPsiDirectory.navigate(true);
      }
      // 创建XML
      VirtualFile virtualFileBuildPath = FileUtil.createDirectories(this, fileByNioFile, buildPath);
      VirtualFile virtualFile = FileUtil.createDirectories(this, virtualFileBuildPath, "WEB-INF", "cfgHome", "plugin", plugID);
      PsiDirectory xmlPsiDirectory = psiManager.findDirectory(virtualFile);
      FileUtil.createXml(project, xmlPsiDirectory, "pluginCfg", values, "/xml/pluginCfg.xml.sample");
      VirtualFile virtualFileSpring = FileUtil.createDirectories(this, virtualFile, "spring");
      PsiDirectory xmlSpringPsiDirectory = psiManager.findDirectory(virtualFileSpring);
      String pluginXmlNmae = "spring-" + plugID + "-plugin";
      FileUtil.createXml(project, xmlSpringPsiDirectory, pluginXmlNmae, values, "/xml/spring/spring-xxx-plugin.xml.sample");
      // 创建MF
      VirtualFile virtualFileMetaInf = FileUtil.createDirectories(this, virtualFileBuildPath, "META-INF");
      PsiDirectory metaPsiDirectory = psiManager.findDirectory(virtualFileMetaInf);
      FileUtil.createOther(project, metaPsiDirectory, "MANIFEST.MF", "Manifest-Version: 1.0");
      // 创建配置文件
      VirtualFile virtualFileIdea = FileUtil.createDirectories(this, fileByNioFile, ".idea");
      boolean pluginInstalled = PluginManagerCore.isPluginInstalled(PluginId.getId("com.jetbrains.plugins.webDeployment"));
      ActionToolUtil.showSync(project, pluginInstalled);
      ConfigEntity configEntity = new ConfigEntity(rootPath, plugID, buildPath, null, "src_" + plugID);
      PsiDirectory ideaPsiDirectory = psiManager.findDirectory(virtualFileIdea);
      if (ideaPsiDirectory == null) {
        ActionToolUtil.showSetting(project);
        return;
      }
      FileUtil.createOther(project, ideaPsiDirectory, ModuleInformation.MODULE_CONFIG, configEntity.finalResult());
    }
  }
}
